package fr.vvins.core.biz.auth;

import java.util.List;
import java.util.Set;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.social.connect.Connection;
import org.springframework.social.connect.support.ConnectionFactoryRegistry;
import org.springframework.social.facebook.api.Facebook;
import org.springframework.social.facebook.api.FacebookProfile;
import org.springframework.social.facebook.api.impl.FacebookTemplate;
import org.springframework.social.facebook.connect.FacebookConnectionFactory;
import org.springframework.social.oauth2.AccessGrant;
import org.springframework.social.oauth2.OAuth2Operations;

import fr.vvins.core.biz.auth.dto.FacebookCredentialDtoImpl;
import fr.vvins.core.biz.user.UserException;
import fr.vvins.core.biz.user.dto.CredentialDto;
import fr.vvins.core.biz.user.dto.UserDto;
import fr.vvins.core.common.TechnicalException;
import fr.vvins.core.common.dto.EntityDtoConverter;
import fr.vvins.core.user.dao.CommunityRepository;
import fr.vvins.core.user.dao.UserCommunityRepository;
import fr.vvins.core.user.dao.UserRepository;
import fr.vvins.core.user.entity.User;
import fr.vvins.core.user.entity.UserCommunity;

public class FacebookAuthManagerImpl implements AuthManager{ 
	@Autowired
	private EntityDtoConverter converter;
	@Autowired
	public ConnectionFactoryRegistry connectionFactoryLocator;
	@Autowired
	private UserRepository userDao;
	@Autowired
	private CommunityRepository communityDao;
	@Autowired
	private UserCommunityRepository userCommunityDao;
	
	public UserDto authenticate(CredentialDto credential) throws UserException, TechnicalException {
		Facebook fb = getFacebookManager(((FacebookCredentialDtoImpl)credential).getAccessToken());
		FacebookProfile p = fb.userOperations().getUserProfile();
		User localUser = userDao.findByCommunityToken(p.getId());
		if(localUser == null){
			localUser = userDao.findByEmail(p.getEmail());
			if(localUser == null){
				localUser = new User();
			}	
			localUser.setEmail(p.getEmail());
			localUser.setLogin(p.getEmail());
			localUser.setDescription(p.getBio());
			localUser.setGender(p.getGender());
			//localUser.set(p.getBirthday());
			localUser.setFirstName(p.getFirstName());
			localUser.setLastName(p.getLastName());
			localUser.setPicture(Facebook.GRAPH_API_URL + p.getUsername()+ "/picture");
			localUser = userDao.save(localUser);
			
			UserCommunity comUser = new UserCommunity();
			comUser.setCommunity(communityDao.findOne(1));
			comUser.setUserCommunityToken(p.getId());
			comUser.setUser(localUser);
			userCommunityDao.save(comUser);
		}
		List<String> friendsId = fb.friendOperations().getFriendIds();
		List<User> friends = userDao.findByCommunityTokens(friendsId);
		List<User> followers = userDao.getFollowers(localUser.getId());	
		Set<User> following = localUser.getFollowingUser();
		
		if(friends != null && friends.size() > 0){
			for(User user : friends){
				if(!followers.contains(user)){
					followers.add(user);
				}
			}
		}
		
		localUser = userDao.save(localUser);
		UserDto dto = new UserDto();
		converter.convertEntityToDto(localUser, dto);
		return dto;
	}
	
	public Facebook getFacebookManager(String accessToken) throws UserException{
		FacebookConnectionFactory connectionFactory = (FacebookConnectionFactory)connectionFactoryLocator.getConnectionFactory("facebook");
		OAuth2Operations oauthOperations = connectionFactory.getOAuthOperations();
		AccessGrant accessGrant = oauthOperations.exchangeForAccess(accessToken, "", null);
		Connection<Facebook> connection = connectionFactory.createConnection(accessGrant);
		return (Facebook) (connection != null ? connection.getApi() : new FacebookTemplate());
	}


	public ConnectionFactoryRegistry getConnectionFactoryLocator() {
		return connectionFactoryLocator;
	}

	public void setConnectionFactoryLocator(ConnectionFactoryRegistry connectionFactoryLocator) {
		this.connectionFactoryLocator = connectionFactoryLocator;
	}

	public EntityDtoConverter getConverter() {
		return converter;
	}

	public void setConverter(EntityDtoConverter converter) {
		this.converter = converter;
	}

	public UserRepository getUserDao() {
		return userDao;
	}

	public void setUserDao(UserRepository userDao) {
		this.userDao = userDao;
	}

	public CommunityRepository getCommunityDao() {
		return communityDao;
	}

	public void setCommunityDao(CommunityRepository communityDao) {
		this.communityDao = communityDao;
	}

	public UserCommunityRepository getUserCommunityDao() {
		return userCommunityDao;
	}

	public void setUserCommunityDao(UserCommunityRepository userCommunityDao) {
		this.userCommunityDao = userCommunityDao;
	}
}
